package edu.zju.gis.dbfg.model.tile;

import edu.zju.gis.dbfg.common.constant.Seprator;
import edu.zju.gis.dbfg.model.PyramidConfig;
import edu.zju.gis.dbfg.model.base.Pipeline;
import edu.zju.gis.dbfg.model.base.PipelineBuilder;
import edu.zju.gis.dbfg.model.base.VectorTileBuilder;
import edu.zju.gis.dbfg.model.datasource.DataReader;
import edu.zju.gis.dbfg.model.datasource.ShpDataReader;
import edu.zju.gis.dbfg.model.io.geojson.GeoJsonTileBuilder;
import edu.zju.gis.dbfg.model.util.TileID;
import edu.zju.gis.dbfg.model.util.TileUtil;
import edu.zju.gis.dbfg.model.util.ZLevelInfo;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.awt.*;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * @author Hu
 * @date 2019/8/30
 **/
public class Tiltest {

  public static void main(String[] args) throws Exception {

    String filename = "D:\\Work\\Study\\GeRenXueXi\\Code\\4_矢量瓦片\\data_宁波北仑_LCRA_polygon\\LCRA.shp";
    String outputDir = "D:\\Work\\Study\\GeRenXueXi\\Code\\4_矢量瓦片\\data_宁波北仑_LCRA_polygon\\geojson\\";
    String layerName= "LCRA";
    DataReader dr = new ShpDataReader();
    dr.filename(filename);
    dr.init();
    String[] headers = dr.getHeaders();
    String crsStr = dr.getCrs();
    CoordinateReferenceSystem crs_read = CRS.parseWKT(crsStr);
    String code = CRS.lookupIdentifier(crs_read, true );
    CoordinateReferenceSystem crs = CRS.decode(code);

    // 瓦片各个方向往外多1个像素的数据，瓦片拼接的时候在边缘会有更好的效果
    int buffer = 1;

    // 定义 tile matrix set
    // 数据范围，投影为数据本身的投影
    Envelope dataEnvelope = new Envelope(121.6476959470001,122.18730555600007,29.70329444400005,29.995453917000077);

    // 定义金字塔网格
    PyramidConfig pyramidConfig = new PyramidConfig.PyramidConfigBuilder()
      .setBaseMapEnv(-180, 180, -90, 90)
      .setCrs(crs)
      .setzLevelRange(0, 12) // 0-12 层
      .build();

    ZLevelInfo[] zLevelInfos = TileUtil.initZLevelInfoPZ(pyramidConfig, dataEnvelope);

    int test_level = 5;
    // 测试第5层
    ZLevelInfo zLevelInfo = zLevelInfos[test_level];
    int tile_x_min = zLevelInfo.getTileRanges()[0];
    int tile_x_max = zLevelInfo.getTileRanges()[1];
    int tile_y_min = zLevelInfo.getTileRanges()[2];
    int tile_y_max = zLevelInfo.getTileRanges()[3];

    for (int tile_x = tile_x_min; tile_x <= tile_x_max; tile_x ++){
      for (int tile_y = tile_y_min; tile_y <= tile_y_max; tile_y ++){
        // 根据格网ID获取envelope
        TileID tileID = new TileID();
        tileID.setX(tile_x);
        tileID.setY(tile_y);
        tileID.setzLevel(test_level);
        Envelope tileEnvelope = TileUtil.createTileBox(tileID, pyramidConfig);

        Pipeline pipeline = getPipeline(crs, buffer, tileEnvelope);
        VectorTileBuilder vectorTileBuilder = new GeoJsonTileBuilder(outputDir, tileID, pyramidConfig);

        String featureWkt = dr.next();
        WKTReader wktReader = new WKTReader();
        int count = 0;
        while(featureWkt!=null){
          String[] fields = featureWkt.split(Seprator.TAB.getValue());

          if(fields[0].equals("6"))
            System.out.println("come in");

          Geometry geometry = wktReader.read(fields[fields.length-1]);
          Geometry finalGeom = pipeline.execute(geometry);

          if(!finalGeom.isEmpty()) {
            count ++;
            String featureId = fields[0];
            String geometryName = fields[0];
            Map<String, Object> properties = new HashMap<>();
            for (int i=1; i<headers.length-1; i++){
              properties.put(headers[i], fields[i]);
            }
            vectorTileBuilder.addFeature(layerName, featureId, geometryName, finalGeom, properties);
          }
          featureWkt = dr.next();
        }
        print(String.format("count = %d", count));
        print(String.format("tile[%d, %d] finish", tile_x, tile_y));
        vectorTileBuilder.build();
        dr.reset();
      }
    }
  }

  /**
   * 构建瓦片中每个像素处理的Pipeline
   * 默认瓦片大小：256 * 256
   * OverSampleFactor = 2
   * 默认目标crs与源crs一致
   */
  private static Pipeline getPipeline(CoordinateReferenceSystem sourceCrs, int buffer, Envelope referenceEnvelop) throws Exception {
    CoordinateReferenceSystem targetCrs = sourceCrs;
    int mapWidth = 256;
    int mapHeight = 256;
    int overSampleFactor = 2;
    // rectangle of the image: width and height
    Rectangle paintArea = new Rectangle(mapWidth, mapHeight);

    // bounding box - in final map (target) CRS
    ReferencedEnvelope renderingArea = new ReferencedEnvelope(referenceEnvelop.getMinX(), referenceEnvelop.getMaxX(), referenceEnvelop.getMinY(), referenceEnvelop.getMaxY(), targetCrs);
    Pipeline pipeline = null;
    try {
      final PipelineBuilder builder =
        PipelineBuilder.newBuilder(
          renderingArea, paintArea, sourceCrs, overSampleFactor, buffer);

      pipeline =
        builder.preprocess()
          .transform(false)
          .clip(true, false)
          .simplify(false)
          .collapseCollections()
          .build();
    } catch (FactoryException e) {
      e.printStackTrace();
    }

    return pipeline;
  }

  private static void testReadShp() throws IOException {
    String filename = "D:\\Work\\Study\\GeRenXueXi\\Code\\4_矢量瓦片\\data_宁波北仑_LCRA_polygon\\LCRA.shp";
    DataReader dr = new ShpDataReader();
    dr.filename(filename);
    dr.init();
    String[] headers = dr.getHeaders();
    Arrays.stream(headers).forEach(System.out::println);
    List<String> result = dr.read();
    result.forEach(System.out::println);
    String srs = dr.getCrs();
    System.out.println(srs);
    dr.close();
  }


  private static void print(String val) {
    System.out.println(val);
  }

}
